package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.login.GuiGuLogin;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private AlbumAttributeValueMapper albumAttributeValueMapper;
	@Autowired
	private AlbumStatMapper albumStatMapper;
	@Autowired
	private TrackInfoMapper trackInfoMapper;
	@Autowired
	private VodService vodService;
	@Autowired
	private RabbitService rabbitService;

	/**
	 * 该接口必须登录才能访问
	 * 内容创作者/运营人员保存专辑
	 * @param albumInfo
	 * @return
	 */
	@GuiGuLogin
	@Transactional(rollbackFor = Exception.class)//默认RuntimeException跟Error回滚事务
	@Override
	public void saveAlbumInfo(AlbumInfo albumInfo, Long userId) {
		//1.封装专辑信息,保存一条记录到专辑信息表(set各种信息)
		//1.1 设置用户id
		albumInfo.setUserId(userId);
		//1.2 设置免费试听集数
		albumInfo.setTracksForFree(5);
		//1.3 设置专辑内容审核状态
		albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);
		//1.4 保存专辑,获取专辑ID
		albumInfoMapper.insert(albumInfo);
		Long albumId = albumInfo.getId();
		//2.封装专辑标签关系集合,保存若干条记录到专辑标签关系表
		//2.1 获取入参中包含的标签列表
		List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
		//调用CollectionUtils工具,判断标签列表是否为空isEmpty
		if (CollectionUtil.isNotEmpty(albumAttributeValueVoList)) {
			//2.2 遍历标签列表封装专辑标签关系列表
			for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
				albumAttributeValue.setAlbumId(albumId);
				//2.3 保存专辑标签关系
				albumAttributeValueMapper.insert(albumAttributeValue);
			}
		}
		//3.封装专辑统计信息,保存4条记录到专辑统计表
		this.saveAlbumInfoStat(albumId,SystemConstant.ALBUM_STAT_PLAY,0);
		this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_SUBSCRIBE, 0);
		this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_BUY, 0);
		this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_COMMENT, 0);
		//4.业务校验,验证专辑内填写相关文本信息是否合法,根据审核结果设置审核状态
		String suggestTitle = vodService.scanText(albumInfo.getAlbumTitle());
		String suggestIntro = vodService.scanText(albumInfo.getAlbumIntro());
		if ("pass".equals(suggestTitle) && "pass".equals(suggestIntro)) {
			//专辑标题内容审核无误修改为审核通过
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
			albumInfoMapper.updateById(albumInfo);
			//5.发送专辑上架MQ消息
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId());
			return;
		}
		//6.发送专辑下架消息
		rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,albumInfo.getId());
		throw new GuiguException(500,"专辑标题或内容存在违规!");
	}


	/**
	 * 保存专辑统计信息
	 * @param albumId 专辑ID
	 * @param statType 统计类型
	 * @param statNum 统计数值 0401-播放量 0402-订阅量 0403-购买量 0403-评论数'
	 */
	@Override
	public void saveAlbumInfoStat(Long albumId, String statType, int statNum) {
		AlbumStat albumStat = new AlbumStat();
		albumStat.setAlbumId(albumId);
		albumStat.setStatType(statType);
		albumStat.setStatNum(statNum);
		albumStatMapper.insert(albumStat);
	}

	/**
	 * 分页查询当前用户专辑列表
	 * @param pageInfo
	 * @param userId
	 * @param albumInfoQuery
	 * @return
	 */
	@Override
	public Page<AlbumListVo> getUserAlbumPage(Page<AlbumListVo> pageInfo, Long userId, AlbumInfoQuery albumInfoQuery) {
		return albumInfoMapper.getUserAlbumPage(pageInfo,userId,albumInfoQuery);
	}

	/**
	 * 根据专辑id删除专辑
	 * @param id
	 * @return
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeAlbumInfo(Long id) {
		//1.判断该专辑是否关联声音-根据专辑id查询声音表数量进行判断
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId,id);
		Long count = trackInfoMapper.selectCount(wrapper);
		if (count > 0) {
			throw new GuiguException(500,"该专辑下存在声音!");
		}
		//2. 删除专辑记录
		albumInfoMapper.deleteById(id);
		//3. 删除统计记录
		LambdaQueryWrapper<AlbumStat> statLambdaQueryWrapper = new LambdaQueryWrapper<>();
		statLambdaQueryWrapper.eq(AlbumStat::getAlbumId,id);
		albumStatMapper.delete(statLambdaQueryWrapper);
		//4. 删除专辑标签记录
		LambdaQueryWrapper<AlbumAttributeValue> attributeValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
		attributeValueLambdaQueryWrapper.eq(AlbumAttributeValue::getAlbumId,id);
		albumAttributeValueMapper.delete(attributeValueLambdaQueryWrapper);
		//5.发送下架消息
		rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, id);
	}

	/**
	 * 根据专辑id查询专辑信息(包括专辑标签列表)
	 * @param id 专辑id
	 * @return 专辑信息
	 */
	@Override
	public AlbumInfo getAlbumInfo(Long id) {
		//根据专辑id查询专辑信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(id);
		//todo 业务校验,校验专辑状态是否为下架状态,只有下架状态专辑才可以被修改
		//2. 根据专辑id查询专辑标签列表
		LambdaQueryWrapper<AlbumAttributeValue> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(AlbumAttributeValue::getAlbumId,id);
		List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueMapper.selectList(wrapper);
		if (CollectionUtil.isNotEmpty(albumAttributeValues)) {
			albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
		}
		return albumInfo;
	}

	/**
	 * 修改专辑信息
	 * @param id 专辑id
	 * @param albumInfo 专辑修改后信息
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateAlbumInfo(AlbumInfo albumInfo) {
		//1. 修改专辑相关信息
		albumInfoMapper.updateById(albumInfo);
		Long albumId = albumInfo.getId();
		//2. 可能需要-修改专辑标签关系
		//3.1 根据专辑id删除专辑标签关系记录
		LambdaQueryWrapper<AlbumAttributeValue> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(AlbumAttributeValue::getAlbumId,albumId);
		albumAttributeValueMapper.delete(wrapper);
		//3.2 重新保存专辑标签关系
		List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
		if(CollectionUtil.isNotEmpty(albumAttributeValueVoList)) {
			//如果标签列表中有值重新遍历保存
			for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
				albumAttributeValue.setAlbumId(albumId);
				albumAttributeValueMapper.insert(albumAttributeValue);
			}
		}
		//对修改后的内容再次进行内容审核
		String suggestTitle = vodService.scanText(albumInfo.getAlbumTitle());
		String suggestIntro = vodService.scanText(albumInfo.getAlbumIntro());
		if ("pass".equals(suggestTitle) && "pass".equals(suggestIntro)) {
			//专辑标题内容审核无误修改为审核通过
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
			albumInfoMapper.updateById(albumInfo);
			//4.发送上架消息
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
			return;
		}
		//5.发送下架消息
		rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumInfo.getId());
		throw new GuiguException(500, "专辑标题或内容存在违规！");
	}


	/**
	 * 该接口必须登录才能访问
	 * 获取当前用户全部专辑列表
	 * @return
	 */
	@GuiGuLogin
	@Override
	public List<AlbumInfo> getUserAllAlbumList(Long userId) {
		//1. 构建查询条件对象
		LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
		//1.1 查询条件
		wrapper.eq(AlbumInfo::getUserId,userId);
		//1.2 排序
		wrapper.orderByDesc(AlbumInfo::getId);
		//1.3 限制记录数(在sql后拼接语句)
		wrapper.last("limit 200");
		//1.4 指定查询列
		wrapper.select(AlbumInfo::getId,AlbumInfo::getAlbumTitle);
		//2. 执行列表查询
		return albumInfoMapper.selectList(wrapper);
	}


	/**
	 * 根据专辑ID查询专辑统计信息
	 * @param albumId
	 * @return
	 */
	@Override
	public AlbumStatVo getAlbumStatVo(Long albumId) {
		return albumInfoMapper.getAlbumStaVo(albumId);
	}


	@Autowired
	private UserFeignClient userFeignClient;

	/**
	 * 基于当前选择购买起始声音得到分集购买列表
	 *
	 * @param userId  用户ID
	 * @param trackId 选择购买声音ID（起始计算参照）
	 * @return [{name:"本集",price:1,trackCount:1}]
	 */
	@Override
	public List<Map<String, Object>> getUserTrackPaidList(Long userId, Long trackId) {
		//1.创建分集购买列表
		List<Map<String, Object>> list = new ArrayList<>();
		//2.根据声音id查询到"起始"待购声音记录,得到当前声音序号,所属专辑id
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Integer orderNum = trackInfo.getOrderNum();
		Long albumId = trackInfo.getAlbumId();
		//3.根据"起始"声音序号获取所有代购买声音列表(可能包含用户已购声音)
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId,albumId);
		wrapper.ge(TrackInfo::getOrderNum,orderNum);
		wrapper.select(TrackInfo::getId);
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);
		//4.远程调用"用户服务"获取用户已购声音列表
		List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(albumId).getData();
		//5.如果存在已购声音id,将已购声音id排除掉得到真正未购买声音列表
		if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
			trackInfoList = trackInfoList.stream()
					.filter(track -> !userPaidTrackIdList.contains(track.getId())).collect(Collectors.toList());
		}
		//6.根据未购买声音列表长度动态构建分集购买列表
		//6.0 根据专辑ID查询专辑价格=声音价格
		BigDecimal price = albumInfoMapper.selectById(albumId).getPrice();
		//6.1 构建"本集"分集购买对象
		Map<String, Object> currMap = new HashMap<>();
		currMap.put("name", "本集");
		currMap.put("price", price);
		currMap.put("trackCount", 1);
		list.add(currMap);
		//6.2 根据未购买声音数量循环最多构建6个分集购买对象（50集）
		int size = trackInfoList.size();
		//例如：size=12 展示 后10集，全集     size=35 展示 后10集 后20集 后30集 全集
		for (int i = 10; i <= 50; i += 10) {
			if (size > i) {
				Map<String, Object> map = new HashMap<>();
				map.put("name", "后" + i + "集");
				map.put("price", price.multiply(BigDecimal.valueOf(i)));
				map.put("trackCount", i);
				list.add(map);
			} else {
				Map<String, Object> map = new HashMap<>();
				map.put("name", "全集(" + size + "集）");
				map.put("price", price.multiply(BigDecimal.valueOf(size)));
				map.put("trackCount", size);
				list.add(map);
				break;
			}
		}
		return list;
	}


	/**
	 * 查询当前用户未购买声音列表
	 *
	 * @param userId     用户ID
	 * @param trackId    点击付费标识声音ID，将该声音作为起始标准
	 * @param trackCount 购买数量
	 * @return 待购声音列表
	 */
	@Override
	public List<TrackInfo> getWaitBuyTrackList(Long userId, Long trackId, Integer trackCount) {
		//1.根据声音ID查询到“起始”待购声音记录，得到当前声音序号、所属专辑ID
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Long albumId = trackInfo.getAlbumId();
		Integer orderNum = trackInfo.getOrderNum();

		//2.远程调用用户服务获取已购买声音ID列表
		List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(albumId).getData();

		//3.获取待购声音列表 查询条件：专辑ID，序号，已购声音ID 。排序字段：序号  。返回数量：购买数量
		LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
		//3.1 等值查询专辑标题
		queryWrapper.eq(TrackInfo::getAlbumId, albumId);
		//3.2 大于等于当前选购声音序号
		queryWrapper.ge(TrackInfo::getOrderNum, orderNum);
		if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
			//3.3 如果存在已购买声音，去除已购买声音ID
			queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
		}
		//3.4 按照声音序号升序
		queryWrapper.orderByAsc(TrackInfo::getOrderNum);
		//3.5 按用户选择购买数量获取声音列表
		queryWrapper.last("LIMIT " + trackCount);
		//3.6 执行查询列：多查询了专辑ID，需要在订单服务进行算价格需要获取专辑中价格
		queryWrapper.select(TrackInfo::getId, TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
		List<TrackInfo> list = trackInfoMapper.selectList(queryWrapper);
		return list;
	}
}

